package org.forex.api.web.async;

import java.io.IOException;
import java.text.MessageFormat;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.forex.api.web.async.AppManager.AppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractAsyncServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4369096137239799531L;

	private Logger log;

	protected void runAsync(AppContext appContext, AsyncContext asyncContext,
			HttpServletRequest request, HttpServletResponse response) {
		AppContext.executor.execute(new AsyncRunnable(appContext, asyncContext, request, response));		
	}
	
	protected AsyncContext createAsyncContext(HttpServletRequest request){
		AsyncContext result=request.startAsync();
		
		result.addListener(new AsyncListener() {
			
			@Override
			public void onTimeout(AsyncEvent arg0) throws IOException {
				debug("Async timeout");					
			}
			
			@Override
			public void onStartAsync(AsyncEvent arg0) throws IOException {
				debug("Async start");						
			}
			
			@Override
			public void onError(AsyncEvent arg0) throws IOException {				
				debug("Async error");	
			}
			
			@Override
			public void onComplete(AsyncEvent arg0) throws IOException {				
				debug("Async complete");	
			}
		});
		
		return result;
	}
	
	protected abstract void doAsync(AppContext appContext,
			AsyncContext asyncContext, HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException;
	
	protected void log(int type,String msg,Object...params){
		if(log==null)
			log=LoggerFactory.getLogger(this.getClass());
		
		switch (type) {
		case 0:
			log.debug(MessageFormat.format(msg, params));
			break;
		case 1:
			log.info(MessageFormat.format(msg, params));
			break;
		case 2:
			log.error(MessageFormat.format(msg, params));
			break;		
		}
	}
	
	public void debug(String s,Object... params){
		log(0,s,params);
	}
	
	public void info(String s,Object... params){
		log(1,s,params);
	}
	
	public void error(String s,Object... params){
		log(2,s,params);
	}

	class AsyncRunnable implements Runnable {

		AppContext appContext;
		AsyncContext asyncContext;
		HttpServletRequest request;
		HttpServletResponse response;

		public AsyncRunnable(AppContext appContext, AsyncContext asyncContext,
				HttpServletRequest request, HttpServletResponse response) {
			super();
			this.appContext = appContext;
			this.asyncContext = asyncContext;
			this.request = request;
			this.response = response;
		}

		public void run() {
			try {
				doAsync(appContext, asyncContext, request, response);
			} catch (ServletException | IOException e) {				
				e.printStackTrace();
			}finally{
				asyncContext.complete();
			}
		}
	}
}
